package net.andersand.games.yatzy;

import java.util.Arrays;

import junit.framework.TestCase;

/**
 * Testharness for Yatzy
 * 
 * @author Anders Sandberg Nordbø
 */
public class YatzyTest extends TestCase {

	private Dice d;
	private ScoreKeeper sk;
	
	public void setUp() throws Exception {
		d = new Dice();
		d.getDice().clear();
		sk = new ScoreKeeper(0);
	}
	
	private Game createGame(String... playerNames) {
		return createGame(null, playerNames);
	}
	
	private Game createGame(YatzyFrame frame, String... playerNames) {
		return new Game(frame, Arrays.asList(playerNames));
	}
	
	// Used to TDD getResults, but as return type was changed
    // it became complicated to maintain these tests	
	public void _testGetResults1() {
		Game game = createGame("Player1", "Player2");
		Player p1 = game.getPlayer(1);
		Player p2 = game.getPlayer(2);
		addScore(p1, ScoreType.YATZY, 30);
		addScore(p2, ScoreType.ONES, 3);
		addScore(p1, ScoreType.FULLHOUSE, 28);
		addScore(p2, ScoreType.TWOS, 6);
		addScore(p1, ScoreType.FOURS, 16);
		assertEquals("Player1 : 74\nPlayer2 : 9\n", game.getResults());
	}

	public void _testGetResults2() {
		Game game = createGame("Player1", "Player2");
		Player p2 = game.getPlayer(4);
		addScore(p2, ScoreType.ONES, 3);
		assertEquals("Player2 : 3\nPlayer1 : 0\n", game.getResults());
	}

	public void _testGetResults3() {
		Game game = createGame("Player1", "Player2", "Player3");
		Player p1 = game.getPlayer(5); // mind the static field Player.players will not be reset between tests!
		Player p2 = game.getPlayer(6);
		Player p3 = game.getPlayer(7);
		addScore(p1, ScoreType.ONES, 3);
		addScore(p2, ScoreType.ONES, 0);
		addScore(p3, ScoreType.ONES, 1);
		addScore(p1, ScoreType.TWOS, 2);
		addScore(p2, ScoreType.TWOS, 4);
		addScore(p3, ScoreType.TWOS, 6);
		assertEquals("Player3 : 7\nPlayer1 : 5\nPlayer2 : 4\n", game.getResults());
	}

	private void addScore(Player player, ScoreType type, int value) {
		Score s = new Score(type);
		s.setValue(value);
		player.getScoreKeeper().addScore(s);
	}

	public void testNotFullHouse() {
		createDice(1, 3, 6, 3, 3);
		boolean isFullHouse = !d.getFullHouse().isEmpty();
		assertFalse(isFullHouse);
	}

	public void testFullHouseThreeOfAKindHigh() {
		createDice(6, 3, 6, 6, 3);
		boolean isFullHouse = !d.getFullHouse().isEmpty();
		assertTrue(isFullHouse);
	}

	public void testFullHousePairHigh() {
		createDice(6, 3, 6, 3, 3);
		boolean isFullHouse = !d.getFullHouse().isEmpty();
		assertTrue(isFullHouse);
	}
	
	public void testSmallStraight() {
		createDice(3, 1, 5, 4, 2);
		boolean isSmallStraight = !d.getSmallStraight().isEmpty();
		assertTrue(isSmallStraight);
	}
	
	public void testNotSmallStraight() {
		createDice(3, 1, 6, 4, 2);
		boolean isSmallStraight = !d.getSmallStraight().isEmpty();
		assertFalse(isSmallStraight);		
	}
	
	public void testLargeStraight() {
		createDice(6, 2, 5, 4, 3);
		boolean isLargeStraight = !d.getLargeStraight().isEmpty();
		assertTrue(isLargeStraight);
	}
	
	public void testNotLargeStraight() {
		createDice(3, 5, 5, 4, 2);
		boolean isLargeStraight = !d.getLargeStraight().isEmpty();
		assertFalse(isLargeStraight);		
	}
	
	private void createDice(int... values) {
		for (int value : values) {
			d.getDice().add(d.new Die(value));
		}
	}

	public void testAnalyzePlainValues() {
		createDice(1, 2, 3, 1, 5);
		assertEquals(2, d.analyze(ScoreType.ONES));
	}
	
	public void testAnalyzePair() {
		createDice(3, 1, 2, 5, 3);
		assertEquals(6, d.analyze(ScoreType.PAIR));
	}
	
	public void testAnalyzeNotPair() {
		createDice(3, 1, 2, 5, 6);
		assertEquals(0, d.analyze(ScoreType.PAIR));
	}
	
	public void testAnalyzeTwoPairs() {
		createDice(2,1,5,5,2);
		assertEquals(14, d.analyze(ScoreType.TWOPAIRS));
	}
	
	public void testAnalyzeNotTwoPairs() {
		createDice(2,1,3,5,2);
		assertEquals(0, d.analyze(ScoreType.TWOPAIRS));	
	}

	/**
	 * <u>1, 1, 1</u>, 2, 3
	 */
	public void testAnalyzeTOAKFirst() {
		createDice(3, 1, 2, 1, 1);
		assertEquals(3, d.analyze(ScoreType.THREEOFAKIND));
	}
	
	/**
	 * 1, <u>3, 3, 3</u>, 6
	 */
	public void testAnalyzeTOAKMiddle() {
		createDice(3, 1, 6, 3, 3);
		assertEquals(9, d.analyze(ScoreType.THREEOFAKIND));
	}

	/**
	 * 1, 2, <u>3, 3, 3</u>
	 */
	public void testAnalyzeTOAKLast() {
		createDice(3, 1, 2, 3, 3);
		assertEquals(9, d.analyze(ScoreType.THREEOFAKIND));
	}

	public void testAnalyzeNotTOAK() {
		createDice(3, 1, 2, 5, 6);
		assertEquals(0, d.analyze(ScoreType.THREEOFAKIND));
	}
	
	/**
	 * <u>5, 5, 5, 5</u>, 6
	 */
	public void testAnalyzeFOAKFirst() {
		createDice(5, 6, 5, 5, 5);
		assertEquals(20, d.analyze(ScoreType.FOUROFAKIND));
	}
	
	/**
	 * 1, <u>5, 5, 5, 5</u>
	 */
	public void testAnalyzeFOAKLast() {
		createDice(5, 1, 5, 5, 5);
		assertEquals(20, d.analyze(ScoreType.FOUROFAKIND));
	}
	
	public void testAnalyzeNotFOAK() {
		createDice(2, 1, 2, 2, 6);
		assertEquals(0, d.analyze(ScoreType.FOUROFAKIND));
	}
	
	/**
	 * Not sure how to test this yet
	 */
	public void testScoreKeeper() {
		Score score = new Score(ScoreType.YATZY);
		score.setValue(50);
		sk.addScore(score);
		assertEquals(50, sk.getScore().iterator().next().getValue());
	}
	
}
